package org.u2ml.app.rest;

import java.util.Collection;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.u2ml.app.business.AttributeService;
import org.u2ml.app.business.ConnectedUserService;
import org.u2ml.app.business.OidService;
import org.u2ml.app.business.ProjectClassService;
import org.u2ml.app.business.ProjectService;
import org.u2ml.app.domain.Attribute;
import org.u2ml.app.domain.Inheritance;
import org.u2ml.app.domain.Oid;
import org.u2ml.app.domain.Project;
import org.u2ml.app.domain.ProjectClass;
import org.u2ml.app.domain.RESTResponse;
import org.u2ml.stack.web.WaitingClients;

@Component
@Path("/classes")
public class ProjectClassResource {
	
	@Autowired
	private ProjectClassService projectClassService;
	@Autowired
	private ProjectService projectService;
	@Autowired
	private OidService oidService;
	@Autowired
	private AttributeService attributeService;
	@Autowired
	private ConnectedUserService connectedUserService;

	@POST
	@Produces(MediaType.TEXT_XML)
	public RESTResponse newProjectClass(ProjectClass c) {
		RESTResponse response = new RESTResponse();
		if (c.getOid() != null || c.getName() == null || c.getName().isEmpty() ||
			c.isUserClass() == null || c.getProjectId() == null) {
			throw new WebApplicationException(Status.BAD_REQUEST);
		}
		Project project = projectService.find(c.getProjectId());
		if (project == null)
			response.setErrorCode("project_not_found");
		else {
			c.setProject(project);
			projectClassService.save(c);
			response.addData(c);
		}
		/** Push **/
		WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(c.getProject()));
		return response;
	}

	@GET
	@Produces(MediaType.TEXT_XML)
	public RESTResponse getAll() {
		RESTResponse response = new RESTResponse();
		response.addAllData(projectClassService.get());
		return response;
	}

	@GET
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{oid}")
	public RESTResponse getOne(@PathParam("oid") Long oid) {
		RESTResponse response = new RESTResponse();
		ProjectClass projectClass = projectClassService.find(oid);
		if (projectClass == null)
			response.setErrorCode("class_not_found");
		else
			response.addData(projectClass);
		return response;
	}
	
	@DELETE
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{oid}")
	public RESTResponse delete(@PathParam("oid") Long id) {
		RESTResponse response = new RESTResponse();
		ProjectClass projectClass = projectClassService.find(id);
		if (projectClass==null)
			response.setErrorCode("class_not_found");
		else {
			projectClassService.delete(projectClass);
			/** Push **/
			WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(projectClass.getProject()));
		}
		return response;
	}
	
	
	@GET
	@Produces(MediaType.TEXT_XML)
	@Path("/project/{oid}")
	public RESTResponse findByProject(@PathParam("oid") Long oid) {
		RESTResponse response = new RESTResponse();
		if (oid == null)
			throw new WebApplicationException(Status.BAD_REQUEST);
		Project project = projectService.find(oid);
		if (project == null)
			response.setErrorCode("user_not_found");
		else
			response.addAllData(projectClassService.getByProject(project));
		return response;
	}

	//Needs to be checked later (when owner is setted)
	@GET
	@Produces(MediaType.TEXT_XML)
	@Path("/project/owner/{oid}")
	public RESTResponse getOwner(@PathParam("oid") Long projectId) {
		RESTResponse response = new RESTResponse();
		Project project = projectService.find(projectId);
		if (project == null)
			response.setErrorCode("project_not_found");
		else
			response.addData(project.getOwner());		
		return response;
	}
	
	/*// INHERITANCE //*/
	
	@GET
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{oid}/inheritance/")
	public RESTResponse getAllParentClasses(@PathParam("oid") Long oid) {
		RESTResponse response = new RESTResponse();
		ProjectClass c = projectClassService.find(oid);
		if (c == null)
			response.setErrorCode("class_not_found");
		else
			response.addAllData(c.getParents());
		return response;
	}
	
	@POST
	@Produces(MediaType.TEXT_XML)
	@Path("/class/inheritance/")
	public RESTResponse addParent(Inheritance inheritance) {
		RESTResponse response = new RESTResponse();
		if (inheritance == null || inheritance.getParentId() == null || inheritance.getChildId() == null)
			throw new WebApplicationException(Status.BAD_REQUEST);
		ProjectClass child = projectClassService.find(inheritance.getChildId());
		Oid parent = oidService.find(inheritance.getParentId());
		
		if(parent == null) {
			parent = new Oid();
			parent.setValue(inheritance.getParentId());
			oidService.saveOid(parent);
		}
		
		if (child.isChildOf(parent))
			response.setErrorCode("this_class_already_parent_of_that_class");
		else {
			child.addParent(parent);
			response.addData(projectClassService.update(child));
			/** Push **/
			WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(child.getProject()));
		}
		return response;
	}
	
	@DELETE
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{oid}/inheritance/{parentId}")
	public RESTResponse removeParent(@PathParam("oid") Long childId, @PathParam("parentId")  Long parentId) {
		RESTResponse response = new RESTResponse();
		if ((childId == null) || (parentId == null))
			throw new WebApplicationException(Status.BAD_REQUEST);
		
		ProjectClass child = projectClassService.find(childId);
		
		if (child == null)
			response.setErrorCode("child_class_not_found");
		else {
			Oid parent = oidService.find(parentId);
			if (parent == null)
				response.setErrorCode("parent_class_not_found");
			else {
				child.removeParent(parent);
				projectClassService.update(child);
				/** Push **/
				WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(child.getProject()));
			}
		}
		
		return response;
	}	
	
	/*// ATTRIBUTES //*/
	
	@GET
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{oid}/attributes/")
	public RESTResponse getAllAttributes(@PathParam("oid") Long oid) {
		RESTResponse response = new RESTResponse();
		ProjectClass c = projectClassService.find(oid);
		if (c == null)
			response.setErrorCode("class_not_found");
		else
			response.addAllData(c.getAttributes());
		return response;
	}
	
	@POST
	@Produces(MediaType.TEXT_XML)
	@Path("/class/attributes/")
	public RESTResponse addAttribute(Attribute attribute) {
		RESTResponse response = new RESTResponse();
		if (attribute == null || attribute.getClassId() == null || attribute.getClassId() == null)
			throw new WebApplicationException(Status.BAD_REQUEST);
		ProjectClass c = projectClassService.find(attribute.getClassId());
		attribute.setParent(c);
		attribute = attributeService.save(attribute);
		c.addAttribute(attribute);
		response.addData(projectClassService.update(c));
		/** Push **/
		WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(c.getProject()));
		return response;
	}
	
	@DELETE
	@Produces(MediaType.TEXT_XML)
	@Path("/class/{classId}/attribute/{attributeId}")
	public RESTResponse removeAttribute(@PathParam("classId") Long classId, @PathParam("attributeId")  Long attributeId) {
		RESTResponse response = new RESTResponse();
		if ((classId == null) || (attributeId == null))
			throw new WebApplicationException(Status.BAD_REQUEST);
		
		ProjectClass c = projectClassService.find(classId);
		
		if (c == null)
			response.setErrorCode("class_not_found");
		else {
			Attribute attribute = attributeService.find(attributeId);
			if (attribute == null)
				response.setErrorCode("attribute_not_found");
			else {
				c.removeAttribute(attribute);
				projectClassService.update(c);
				/** Push **/
				WaitingClients.wakeUpSessions(connectedUserService.contributorSessions(c.getProject()));
			}
		}
		
		return response;
	}
	
}
